/*
 * DynamicArithmeticDescompresor.cpp
 *
 *  Created on: 01/12/2009
 *      Author: hernan
 */

#include "DynamicArithmeticDescompresor.h"

DynamicArithmeticDescompresor::DynamicArithmeticDescompresor() {

	this->contextTable =  new ContextTable(256);
	this->bitManager = new BitManager();
}

DynamicArithmeticDescompresor::~DynamicArithmeticDescompresor() {
	delete this->contextTable;
	delete this->bitManager;
}


char DynamicArithmeticDescompresor::getRoofByNumber(unsigned int number, char contexto, unsigned int length){

	unsigned char caracter;

	bool encontro = false;

	int i = 0;

	while ((encontro==false)&&(i<256)){

		caracter = static_cast <char> (i);

		long double probability = this->getContextTable()->getAcummulatedProbability(contexto,caracter);

		unsigned int techoAux = CompresorUtil::calculateNewRoof(probability,length,this->getFloor());

		if (techoAux >= number)
		{
			return caracter;
		}

		i++;
	}

	return ' ';
}


string DynamicArithmeticDescompresor::doUncompress(){

	string cadenaDescomprimida;

	unsigned char contexto = 'e';

	this->getBitManager()->setStringToDecompress(this->stringToUncompress);

	unsigned int posicion;

	//bool fin = false;

	//unsigned int cero = 0;

	unsigned int max = ~0;

	this->setRoof(max);

	this->setFloor(0);

	unsigned char caracterDescomprimido;

	unsigned int i=0;

	posicion = this->getBitManager()->getIntToDescompress(); // Se obtiene el proximo entero

	while (!this->bitManager->isFinDescompresion()) {

		unsigned int length = CompresorUtil::calculateLength(this->getFloor(), this->getRoof());

		caracterDescomprimido = this->getRoofByNumber(posicion,contexto,length);


		int caracterInt = static_cast <int> (caracterDescomprimido);

		caracterInt =  caracterInt - 1;

		unsigned char caracterAnterior = static_cast <char> (caracterInt);

		double probability = this->getContextTable()->getAcummulatedProbability(contexto,caracterAnterior); //Obtiene la probabilidad del caracter anterior al obtenido

		unsigned int techo = ceil(CompresorUtil::calculateNewRoof(probability,length, this->getFloor()));

		probability = this->getContextTable()->getAcummulatedProbability(contexto,caracterDescomprimido); // Se calcula el techo del caracter obtenido

		this->setRoof(floor(CompresorUtil::calculateNewRoof(probability,length,this->getFloor()))); // Se calcula el techo del caracter obtenido


		this->setFloor(CompresorUtil::calculateNewFloor(techo)); // El techo obtenido pasa a ser el piso del caracter obtenido

		this->getContextTable()->updateTable(contexto,caracterDescomprimido); // Se actualiza tabla de contextos

		contexto = caracterDescomprimido;

		cadenaDescomprimida.push_back(caracterDescomprimido);

		this->getBitManager()->setFloor(this->getFloor());

		this->getBitManager()->setRoof(this->getRoof());

		this->getBitManager()->normalize();

		this->setFloor(this->getBitManager()->getNormalizedFloor()); // Se normalizan piso y techo

		this->setRoof(this->getBitManager()->getNormalizedRoof());

		posicion = this->getBitManager()->getIntToDescompress(); // Se obtiene el proximo entero
		i++;
	}

	return cadenaDescomprimida;



}

unsigned int DynamicArithmeticDescompresor::getFloor() const{

	return this->Floor;

}

unsigned int DynamicArithmeticDescompresor::getRoof() const{

	return this->roof;

}

void DynamicArithmeticDescompresor::setFloor(unsigned int floor){

	this->Floor = floor;

}

void DynamicArithmeticDescompresor::setRoof(unsigned int roof){

	this->roof = roof;

}

ContextTable* DynamicArithmeticDescompresor::getContextTable() const{

	return this->contextTable;

}

void DynamicArithmeticDescompresor::setBitManager(BitManager* bitManager){

	this->bitManager = bitManager;

}

BitManager* DynamicArithmeticDescompresor::getBitManager() const{

	return this->bitManager;

}

string DynamicArithmeticDescompresor::getStringToUncompress() const{

	return this->stringToUncompress;

}

void DynamicArithmeticDescompresor::setStringToUncompress(string stringToUncompress){

	this->stringToUncompress = stringToUncompress;

}


